.global _start
.global _bss_start
_bss_start:
    .word __bss_start

.global _bss_end
_bss_end:
.word __bss_end

_start:
    ; 复位中断函数 
    ldr pc, =Reset_Handler
    ; 未定义指令中断
    ldr pc, =Undefined_Handler
    ; SVC
    ldr pc, =SVC_Handler
    ; 预取终止
    ldr pc, =PreAbort_Handler
    ; 数据终止
    ldr pc, =DataAbort_Handler
    ; 未使用
    ldr pc, =NotUsed_Handler
    ; IRQ
    ldr pc, =IRQ_Handler
    ; FIQ
    ldr pc, =FIQ_Handler

Reset_Handler:
    ; ldr r0, =Reset_Handler
    ; bx r0

    ; 关闭所有中断
    cpsid i

    ; 关闭 I\D Cache 和 MMU, 修改 SCTLR 寄存器  采用 读改写 方式
   
    ;  读取 SCTLR 寄存器的数据到 R0 寄存器里面
    MRC p15, 0, r0, c1, c0, 0

    ; 关闭ICache
    bic r0, r0, #(1 << 12)
    ; 关闭分支预测
    bic r0, r0, #(1 << 11)
    ; 关闭DCache
    bic r0, r0, #(1 << 2)
    ; 关闭对其
    bic r0, r0, #(1 << 1)
    ; 关闭MMU
    bic r0, r0, #(1 << 0)

    ; 将 R0 内容写入 SCTLR
    MCR p15, 0, r0, c1, c0, 0

    ; 设置中断偏移
    ldr r0, =0x87800000
    dsb
    isb
    ; 设置 VBAR 寄存器 = 0x87800000
    MCR p15,0,r0,c12,c0,0
    dsb
    isb

        
    ; 清除BS段
    ldr r0, _bss_start
    ldr r1, _bss_end
    mov r2, #0

bss_loop:
    stmia r0!, {r2}
    cmp r0, r1
    ble bss_loop

    ; 设置处理器进入IRQ模式
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x12
    msr cpsr, r0
    ldr sp, =0x80600000

    ; 设置处理器进入SYS模式
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x1f
    msr cpsr, r0
    ldr sp, =0x80400000
    
    ; 设置处理器进入SVC模式
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0x13
    msr cpsr, r0
    ldr sp, =0x80200000

    ; 打开中断
    cpsie i

    ; 跳转到 C 语言主函数 
    b main

Undefined_Handler:
    ldr r0, =Undefined_Handler
    bx r0

SVC_Handler:
    ldr r0, =SVC_Handler
    bx r0

PreAbort_Handler:
    ldr r0, =PreAbort_Handler
    bx r0

DataAbort_Handler:
    ldr r0, =DataAbort_Handler
    bx r0

NotUsed_Handler:
    ldr r0, =NotUsed_Handler
    bx r0

IRQ_Handler:
    ; ldr r0, =IRQ_Handler
    ; bx r0
    push {lr}           /*保存1r地址*/
    push {r0-r3, r12}   /*保存r0-r3， r12寄存器*/ 
    mrs r0, spsr        /*读取spsr寄存器*/
    push {r0}           /*保存spsr寄存器*/

    mrc p15, 4, rl, c15, cO, 0  /*从CP15的C0寄存器内的值到R1寄存器中
                                    参考文档ARM Cortex-A(armV7)编程手册V4.0.p
                                    Cortex-A7 Technical Refe renceManua . pdf*/
    add r1, r1, #0X2000         /* GIC基地址加0X2000, 也就是GIC的CPU接口端基 */
    Ldr r0, [r1, #0XC]          /* GIC的CPU接口端基地址加0X0C就是GICC_ IAR寄在
                                    GICC IAR寄存器保存这当前发生中断的中断号，
                                    这个中断号来绝对调用哪个中断服务函数 */
    push {r0, r1}               /*保存r0,r1 */
    cps #0x13                   /*进入SVC模式，允许其他中断再次进去*/
    push {Lr}                   /* 保存SVC模式的1r寄存器 */
    ldr r2, =system_irqhandler  /*加载C语言中断处理函数到r2寄存器中*/

    blx r2                      /* 运行C语 言中断处理函数，带有一个参数，保存在R0 */
    pop {lr}                    /* 执行完C语 言中断服务函数， lr出栈*/
    cps #0x12                   /*进入IRQ模式*/
    pop {r0, r1}
    str r0, [r1, #0X10]         /* 中断执行完成， 写EOIR */
    pop {r0}

    str r0, [r1, #0X10]         /* 中断执行完成， 写EOIR */
    pop {r0}
    msr spsr cxsf, r0           /*恢复spsr */
    pop {r0-r3, r12}            /* r0-r3,r12出栈 */ 
    pop {lr}                    /* lr出栈*/
    subs pc, lr, #4             /*将lr-4赋给pc */


FIQ_Handler:
    ldr r0, =FIQ_Handler
    bx r0

    ; 设置处理器进入SVC模式
    ; mrs r0, cpsr
    ; bic r0, r0, #0x1f
    ; orr r0, r0, #0x13
    ; msr cpsr, r0
